#include "TcpClient.h"
#include<iostream>
#include "SocketOpt.h"
using namespace tmms::network;


TcpClient::TcpClient(EventLoop * loop,const InetAddress &server)
:TcpConnection(loop,-1,InetAddress(),server),server_addr_(server)
{

}

TcpClient::~TcpClient()
{
    OnClose();
}


void TcpClient::Connect()
{
    loop_->RunInLoop([this](){ //保证在同一个事件循环中
        ConnectInLoop ();
    });
}

void TcpClient::ConnectInLoop()
{
    loop_->AssertInLoopThread();
    fd_= SocketOpt::CreateNonblockingTcpSocket(AF_INET);
    if(fd_<0)
    {
        OnClose();
        return ;
    }
    status_ = KTcpConStatusConnecting;
    loop_ ->AddEvent(std::dynamic_pointer_cast<TcpClient>(shared_from_this()));
    EnableWriting(true);
    SocketOpt opt(fd_);
    int ret = opt.Connetct(server_addr_);//自己是客户端去连接srever端
    if(ret == 0)
    {
        UpdateConnectionStatus();
    }else if(ret == -1)
    {
        if(errno != EINPROGRESS)
        {
            NEWORK_ERROR <<"connect ot server :"<<server_addr_.ToIpPort()<<"is faild";
            OnClose();
            return ;
        }
    }

}

void TcpClient::SetConnectCallback(const ConnectionCallback &cb)
{
    connected_cb_ = cb;
}

void TcpClient::SetConnectCallback(ConnectionCallback &&cb)
{
    connected_cb_ = std::move(cb);
}

void TcpClient::UpdateConnectionStatus()
{
    status_ = KTcpConStatusConnected;
    if(connected_cb_)
    { //执行连接成功的回调函数
        connected_cb_(std::dynamic_pointer_cast<TcpClient>(shared_from_this()),true);
    }
}

bool TcpClient::CheckError()
{
    int error =0;
    socklen_t len = sizeof(error);
    ::getsockopt(fd_,SOL_SOCKET,SO_ERROR,&error,&len);
    return error != 0;
}

void TcpClient::OnRead()
{
    if(status_ == KTcpConStatusConnecting)
    {
        if(CheckError())
        {
            NEWORK_ERROR<<"connect to server:"<<server_addr_.ToIpPort()<<"error:";
            OnClose();
            return;
        }
        UpdateConnectionStatus();
        return ;
    }
    if(status_ == KTcpConStatusConnected)
    {
        TcpConnection::OnRead();
    }
}

void TcpClient::OnWrite() 
{
    if(status_ == KTcpConStatusConnecting)
    {
        if(CheckError())
        {
            NEWORK_ERROR<<"connect to server:"<<server_addr_.ToIpPort()<<"error:";
            OnClose();
            return;
        }
        UpdateConnectionStatus();
        return ;
    }
    if(status_ == KTcpConStatusConnected)
    {
        TcpConnection::OnWrite();
    }
}

void TcpClient::OnClose() 
{
    if(status_ == KTcpConStatusConnecting ||
         status_ == KTcpConStatusConnected)
    {
        loop_->DelEvent(std::dynamic_pointer_cast<TcpClient>(shared_from_this()));
    }
    status_ = KTcpConStatusConnected;
    TcpConnection::OnClose();
}

void TcpClient::Send(std::list<BufferNodePtr>&list)
{
    if(status_ == KTcpConStatusConnected)
    {
        TcpConnection::Send(list);
    }
}

void TcpClient::Send(const char * buf,size_t size)
{
    if(status_ == KTcpConStatusConnected)
    {
        TcpConnection::Send(buf,size);
    }
}